<?php

/**
 * Description of Task
 *
 * @author prometheus
 */
abstract class Task extends x10_Manager
{
	public $xName = 'Feladatkezelő';

	/**
	 * @var x10_StateManager
	 */
	protected $stateMan;

	/**
	 * @var Task
	 */
	protected $itemObject;

	protected $displays;

	protected $routers = array();

	protected $routerObjects = array();

/////////////////////////////////////////////////////////////////
// Task_Item
	/**
	 * @var Task_ItemProvider
	 */
	protected $provider;
	
	/**
	 * Az aktuálisan kiválasztott megjelenítő.
	 * @var XDD_Provider
	 */
	protected $activeDisplay;

	/**
	 * A sikeresen visszatérő útvonalválasztó.
	 * @var UAL_Router
	 */
	protected $selectedRouter;

	/**
	 * Felhasználó által megadott akció paraméterek (csak akció végrehajtásakor),
	 * @var Array
	 */
	protected $parameters = array();

	/**
	 * @var Task
	 */
	protected $parent;

	/**
	 * @var UAL_Request
	 */
	protected $request;

	/**
	 * A felhasználó által megadott argumentumok (pl. HTTP paraméterek).
	 * @var Array
	 */
	protected $userArguments = array();
// Task_Item
/////////////////////////////////////////////////////////////////

	public function __construct(x10_Config $config=NULL)
	{
		parent::__construct($config);
		$this->registerProvider(new x10_Provider_Descriptor('Task_ItemProvider'));

		$this->routers = $this->config->getConfigKey('routers');
		$this->stateMan = x10::dedicate('x10_StateManager');
		$this->request = x10::dedicate('UAL_Request');

		$this->userArguments = $this->request[$this->request->method]->get()->arguments;

		$displays = $this->config->getConfigKey('displays');
		if (!is_null($displays)) $this->displays = $displays;
	}

/////////////////////////////////////////////////////////////////
// Task_Item
	/**
	 * Ha a taszk elemként van használva egy másik taszk listájában, ezzel
	 * a metódussal kell beállítani a hozzátartozó elemszolgáltatót.
	 * @param Task_ItemProvider $provider
	 */
	public function setProvider(Task_ItemProvider $provider)
	{
		$this->provider = $provider;
	}

	/**
	 * @return Task_ItemProvider
	 */
	public function getProvider()
	{
		return $this->provider;
	}

	/**
	 * Ha a taszk elemként van használva egy másik taszk listájában, ezzel
	 * a metódussal lehet beállítani a taszkhoz tartozó felhasználói
	 * argumentumokat.
	 * @param Array $arguments
	 */
	public function setUserArguments($arguments)
	{
		$this->userArguments = $arguments;
	}

	/**
	 * Beállítja a taszk gyakorlati szülőjét, azaz azt az objektumot, amelyik a
	 * taszkot létrehozta.
	 * @param Task $parent
	 */
	public function setParent($parent)
	{
		$this->parent = $parent;
	}

	/**
	 * Visszatér a taszkot létrehozó objektummal.
	 * @return Task
	 */
	public function getParent()
	{
		return $this->parent;
	}
	
	/**
	 * A végrehajtási kód helye.
	 * Abban az esetben kerülhet meghívásra, ha a taszk maga is akció.
	 */
	public function action()
	{

	}
// Task_Item
/////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////
// Task_Application
	/**
	 * Visszatér az (al)alkalmazás elemnevének megfelelő standard osztálynévvel.
	 * Az elemhez a szülői ágon legközelebb eső alkalmazás fogja visszaadni
	 * ezt az értéket.
	 * @param String $application
	 * @return String
	 */
	public function getStdAppClassName($application)
	{
		return $this->parent->getStdAppClassName($application);
	}

	/**
	 * Visszatér a taszk elemnevének megfelelő standard osztálynévvel.
	 * Az elemhez a szülői ágon legközelebb eső alkalmazás fogja visszaadni
	 * ezt az értéket.
	 * @param String $task
	 * @return String
	 */
	public function getStdTaskClassName($task)
	{
		return $this->parent->getStdTaskClassName($task);
	}

	/**
	 * Visszatér a taszk egy akciójának elemneve szerint alkotott standard
	 * osztály nevével.
	 * Az elemhez a szülői ágon legközelebb eső alkalmazás fogja visszaadni
	 * ezt az értéket.
	 * @param String $task
	 * @param String $action
	 * @return String
	 */
	public function getStdActionClassName($task, $action)
	{
		return $this->parent->getStdActionClassName($task, $action);
	}
// Task_Application
/////////////////////////////////////////////////////////////////

	/**
	 * Visszaadja a felhasználó által kiválasztott megjelenítő nevét, vagy az
	 * alapértelmezett megjelenítő nevét.
	 * @return String
	 */
	public function getUserDisplayName()
	{
		$result = $this->displays->default;
		$mode = 'lastParameter';
		if (isset($this->displays->selectMode) and isset($this->displays->selectMode->by))
		{
			$mode = $this->displays->selectMode->by;
		}
		switch ($mode)
		{
			case 'lastParameter':
			{
				$result = $this->parameters[count($this->parameters)-1];
				break;
			}
			case 'argument':
			{
				if (isset($this->displays->selectMode->argName))
				{
					$args = $this->request[$this->request->method]->get()->arguments;
					$argName = $this->displays->selectMode->argName;
					if (isset($args[$argName]))
					{
						$result = $args[$argName];
					}
				}
				break;
			}
		}
		return $result;
	}

	/**
	 * Visszaadja az alkalmazáshoz regisztrált taszkok osztályneveit.
	 * @return Array
	 */
	protected function getRegisteredItems()
	{
		return (array)$this->config->getConfigKey('registeredItems');
	}

	/**
	 * Visszaadja a felhasználó által megadott argumentumokat.
	 * @return Array
	 */
	public function getUserArguments()
	{
		return array_merge($this->userArguments);
	}

	/**
	 * A beállítások szerint engedélyezett azonosítóhoz társított megjelenítő
	 * szolgáltató példánnyal tér vissza.
	 * @param String $disp
	 * @param Bool $activate Amennyiben TRUE, ez lesz a kiválasztott megjelenítő
	 * is (alapértelmezés) - FALSE esetén csak visszatér.
	 * @return XDD_Provider
	 */
	public function selectDisplay($disp=NULL, $activate=TRUE)
	{
		$dispClass = NULL;
		$activeDisplay = NULL;
		if (is_null($disp))
		{
			$disp = $this->getUserDisplayName();
		}

		if (
			isset($this->displays->settings) and
			isset($this->displays->settings->$disp) and
			isset($this->displays->settings->$disp->provider) and
			class_exists($this->displays->settings->$disp->provider)
		)
		{
			unset($this->activeDisplay);
			$dispClass = $this->displays->settings->$disp->provider;
			$dispCfg = isset($this->displays->settings->$disp->config)?
				$this->displays->settings->$disp->config : NULL;

			$activeDisplay = new $dispClass();
			$activeDisplay->getConfig()->override(new x10_Config(new x10_ConfigWrapper($dispCfg)));

			if ($activate)
			{
				$this->activeDisplay = $activeDisplay;
			}
		}

		return $activeDisplay;
	}

	/**
	 * Visszaadja az aktuális megjelenítőt.
	 * @return XDD_Provider
	 */
	public function getDisplay()
	{
		return $this->activeDisplay;
	}

	/**
	 * Megjeleníti a kapott adatokat az aktuális megjelenítővel.
	 * @param Array $data
	 * @param Bool $override Amennyiben TRUE, a meglévő adatokat felülírja az
	 * újakkal de a nem felülírtak megmaradnak (alapértelmezés) - FALSE esetén
	 * a régi adatokat az újakra cseréli, minden régi adat elvész.
	 */
	public function display($data=array(), $override=TRUE)
	{
		if ($override)
		{
			$this->activeDisplay->overrideData($data);
		}
		else
		{
			$this->activeDisplay->setData($data);
		}

		// TODO - Ezt valami emberibbre kéne cserélni azért...
		header('Content-type: '.$this->activeDisplay->contentType);
		//$this->activeDisplay->overrideData($result);
		$this->activeDisplay->init();
		echo($this->activeDisplay);
	}

	/**
	 * Inicializálja a taszkot.
	 * Meghívja az útvonalválasztókat, eltárolja az útvonalakból hátramaradt
	 * elemeket (ezek a taszk akcióinak paraméterei lesznek), valamint beállítja
	 * az alapértelmezett megjelenítőt, felfűz minden regisztrált alelemet.
	 */
	public function init()
	{
		if (count($this->routers) == 0) throw new Task_E_Task_NoRouters(get_class($this));

		// Útvonalválasztás
		foreach ($this->routers as $routerClass)
		{
			$router = new $routerClass(NULL, $this);
			$this->routerObjects[] = $router;

			$target = $router->handle();
			if (is_object($target) and ($target instanceof Task || $target instanceof Task_Item))
			{
				$this->selectedRouter = $router;
			}
		}

		// Paraméterek képzése a megmaradt útvonalból
		$this->parameters = $this->selectedRouter->getQueue();

		// Alapértelmezett megjelenítő kiválasztása
		$this->selectDisplay();

		// Alelemek felfűzése
		foreach ($this->getRegisteredItems() as $k=>$v)
		{
			$this[$k] = new Task_ItemProvider(
				new x10_Config(
					array(
						'itemName'		=> $k,
						'itemClass'		=> $v,
						'parentTask'	=> $this,
						'arguments'		=> $this->getUserArguments(),
						'parameters'	=> $this->parameters
					)
				)
			);
			if ($this->selectedRouter->getShifted() == $k)
			{
				$this->itemObject = $this[$k]->get();
			}
		}
	}

	public function run($task='')
	{
		$result = NULL;
		$task = NULL;
		
		if (empty($task))
		{
			$task = $this->selectedRouter->getShifted();
		}

		if (isset($this[$task]))
		{
			$result = $this[$task]->call();
		}

		if (is_null($this->parent))
		{
			$this->display($result);
		}
		else
		{
			return $result;
		}
	}

	public function done()
	{
		
	}

	/**
	 * Belső kliens-átirányítás.
	 * @param String $toLocalURL
	 */
	public function r($toLocalURL='')
	{
		$dr = str_replace('\\', '/', dirname($_SERVER['SCRIPT_NAME']));
		if ($dr != '/') $dr .= '/';
		header('Location: '.$dr.$toURL);
		$this->done();
		x10::done();
	}
}

?>